package org.seeplnframework.skyeye.common.util;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.Lists;
import com.jakewharton.retrofit2.adapter.reactor.ReactorCallAdapterFactory;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.seeplnframework.skyeye.common.alarmmerge.PushAlarmMessageTask;
import org.seeplnframework.skyeye.common.constants.SysConstant;
import org.seeplnframework.skyeye.common.enums.LogLevelEnum;
import org.seeplnframework.skyeye.common.enums.MDCConstantEnum;
import org.seeplnframework.skyeye.common.model.FeiShuAlertMessage;
import org.seeplnframework.skyeye.common.model.WechatConfigData;
import org.seeplnframework.skyeye.common.model.WechatMarkDownMessage;
import org.seeplnframework.skyeye.common.model.WechatMessage;
import reactor.core.publisher.Mono;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Slf4j
public class WeTalkUtils {

    private static final ThreadPoolExecutor alarm = new ThreadPoolExecutor(
            5,
            5,
            60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),
            new ThreadPoolExecutor.DiscardPolicy()
    );

    private static final ThreadPoolExecutor reminder = new ThreadPoolExecutor(
            5,
            5,
            60,
            TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(1000),
            new ThreadPoolExecutor.DiscardPolicy()
    );

    /**
     * 微信服务接口（retrofit2-reactor-adapter：https://github.com/JakeWharton/retrofit2-reactor-adapter）
     * <p>
     * 飞书webhook https://open.feishu.cn/open-apis/bot/v2/hook/e13a94a6-a01e-4da6-a195-c2ecae4919c6
     */
    public static WeTalkService weTalkService = new Retrofit.Builder()
            .baseUrl("https://open.feishu.cn/open-apis/bot/v2/hook/")
            .client(initOkHttpClient())
            .addConverterFactory(new StringConverterFactory())
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(ReactorCallAdapterFactory.create())
            .build()
            .create(WeTalkService.class);

    /**
     * 微信机器人标识
     */
    private static final String WEBHOOK_INDEX = "WEBHOOK_INDEX";
    /**
     * 微信机器人发送消息url
     */
    private static final String WEBHOOK_SEND_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send";

    /**
     * 发送微信消息
     * @param wechatMessage
     */
    public static void sendMessage(WechatMessage wechatMessage) {
        //将markDownMessage适配到feiShuAlertMessage
        if (wechatMessage instanceof WechatMarkDownMessage) {
            FeiShuAlertMessage body = new FeiShuAlertMessage();
            FeiShuAlertMessage.Content detail = new FeiShuAlertMessage.Content();
            detail.setText(((WechatMarkDownMessage) wechatMessage).getMarkdown().getContent());
            body.setContent(detail);
            body.setTargetHook(((WechatMarkDownMessage) wechatMessage).getTargetHook());
            body.setBusinessReminder(((WechatMarkDownMessage) wechatMessage).isBusinessReminder());
            wechatMessage = body;
        }
        try {
            String level = wechatMessage.getLevel();
            String alarmWeTalk = StringUtils.isNotBlank(level) && level.equals(LogLevelEnum.SERIOUS.name())
                    ? ConfigUtils.getProperty(SysConstant.ALARM_SERIOUS_WETALK, "")
                    : ConfigUtils.getProperty(SysConstant.ALARM_WETALK, "");
            if (StringUtils.isBlank(alarmWeTalk)) {
                log.warn("log skyeye >>> config '{}' or '{}' is null", SysConstant.ALARM_WETALK, SysConstant.ALARM_SERIOUS_WETALK);
                return;
            }
            List<WechatConfigData> wechatConfigDataList = Lists.newArrayList();
            if (JSONUtil.isJsonArray(alarmWeTalk)) {
                wechatConfigDataList = JSONUtil.toList(JSONUtil.parseArray(alarmWeTalk), WechatConfigData.class);
            } else {
                List<String> keyList = StrUtil.splitTrim(alarmWeTalk, ",");
                for (String key : keyList) {
                    WechatConfigData wechatConfigData = new WechatConfigData();
                    wechatConfigData.setWebHook(WEBHOOK_SEND_URL);
                    wechatConfigData.setKey(key);
                    wechatConfigDataList.add(wechatConfigData);
                }
            }
            //报警群地址 消息中指定了报警群优先使用指定的 没指定默认从配置的报警群中顺序取第一个
            String firstHook = wechatConfigDataList
                    .stream()
                    .filter(it -> !it.isReminder())
                    .map(WechatConfigData::getKey)
                    .findFirst()
                    .orElse("");
            FeiShuAlertMessage alarm = ((FeiShuAlertMessage) wechatMessage);
            send(alarm.isBusinessReminder(), StringUtils.isEmpty(alarm.getTargetHook()) ? firstHook : alarm.getTargetHook(), wechatMessage.toString());
        } catch (Exception e) {
            log.warn("log skyeye >>> WeTalkUtils.sendMessage occur exception", e);
        }
    }

    /**
     * 发送
     * @param webHookKey
     * @param jsonContent
     */
    private static void send(boolean businessReminder, String webHookKey, String jsonContent) {
        //int currentIndex = getIndex(wechatConfigDataList.size());
        //WechatConfigData wechatConfigData = wechatConfigDataList.get(currentIndex);
        //String key = wechatConfigData.getKey();
        //if (StringUtils.isBlank(key)) {
            //Map<String, String> paramMap = HttpUtil.decodeParamMap(wechatConfigData.getWebHook(), CharsetUtil.defaultCharset());
            //key = paramMap.get("key");
        //}
        //send(key, jsonContent);
        if (StringUtils.isEmpty(webHookKey)) {
            log.warn("sky eye the feishu web hook not matched, so skip this alarm.");
            return;
        }
        if (businessReminder) {
            reminder.submit(new PushAlarmMessageTask(webHookKey, jsonContent));
        } else {
            alarm.submit(new PushAlarmMessageTask(webHookKey, jsonContent));
        }
    }

    /**
     * 发送
     * @param key
     * @param jsonContent
     */
//    private static boolean send(String key, String jsonContent) {
//        try {
//            Long timestamp = System.currentTimeMillis();
//            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), jsonContent);
//            log.info("log skyeye >>> send wechat key: {}, timestamp: {}", key, timestamp);
//            Mono<Response<ResponseBody>> mono = weTalkService.robotSendMono(key, requestBody);
//            ResponseBody responseBody = mono.blockOptional().map(Response::body).orElse(null);
//            String string = responseBody != null ? responseBody.string() : "";
//            log.info("log skyeye >>> send wechat result: {}", string);
//            if (StringUtils.isBlank(string) || string.contains("<!DOCTYPE html>")) {
//                return false;
//            }
//            JSONObject result = JSONUtil.parseObj(string);
//            if (result.get("errcode") == null || !"0".equals(String.valueOf(result.get("errcode")))) {
//                return false;
//            }
//            return true;
//        } catch (Exception e) {
//            log.warn("log skyeye >>> WeTalkUtils.send occur exception", e);
//            return false;
//        }
//    }

    /**
     * 初始化OkHttpClient实例
     * @return
     */
    private static OkHttpClient initOkHttpClient() {
        return new OkHttpClient.Builder()
                .connectionPool(new ConnectionPool())
                .retryOnConnectionFailure(true)
                .connectTimeout(1000, TimeUnit.MILLISECONDS)
                .readTimeout(1000, TimeUnit.MILLISECONDS)
                .writeTimeout(1000, TimeUnit.MILLISECONDS)
                .build();
    }

    /**
     * 获取第几个机器人
     * @param totalCount
     * @return
     */
    private static synchronized int getIndex(int totalCount) {
        int currentIndex = LocalCacheUtils.getIntCache(WEBHOOK_INDEX);
        if (currentIndex > totalCount - 1) {
            currentIndex = 0;
            LocalCacheUtils.putIntCache(WEBHOOK_INDEX, currentIndex);
        }
        LocalCacheUtils.incr(WEBHOOK_INDEX);
        return currentIndex;
    }

    public static void main(String[] args) {
        List<WechatConfigData> wechatConfigDataList = new ArrayList<>();
        WechatConfigData wechatConfigData1 = new WechatConfigData();
        wechatConfigData1.setWebHook("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=e9a44cf0-c2c0-4acc-994a-88fc2774468d");
        wechatConfigData1.setKey("e9a44cf0-c2c0-4acc-994a-88fc2774468d");
        WechatConfigData wechatConfigData2 = new WechatConfigData();
        wechatConfigData2.setWebHook("https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=05e447e6-4545-4c31-a2b3-bd92c13482ef");
        wechatConfigData2.setKey("05e447e6-4545-4c31-a2b3-bd92c13482ef");
        wechatConfigDataList.add(wechatConfigData1);
        wechatConfigDataList.add(wechatConfigData2);

        WechatMarkDownMessage message = new WechatMarkDownMessage();
        String exceptionMessage;
        String exceptionStackTrace;
        try {
            throw new RuntimeException("异常message");
        } catch (Exception e) {
            exceptionMessage = e.getMessage();
            exceptionStackTrace = ExceptionUtils.getStackTrace(e);
        }
        exceptionStackTrace = StrUtil.subBefore(exceptionStackTrace, System.getProperty("line.separator"), true);
        String content = "## **" + MDCConstantEnum.ERROR_MESSAGE.getName() + "：" + "出错啦！" + "**" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.SERVER_NAME.getName() + "**：" + "localhost" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.SOURCE_IP.getName() + "**：" + "10.155.8.91" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.SERVER_IP.getName() + "**：" + "10.155.8.91" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.SERVER_HOSTNAME.getName() + "**：" + "zuomengjun" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.OCCURRENCE_TIME.getName() + "**：" + "2020-06-23 14:20:05" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.REQUEST_TYPE.getName() + "**：" + "http GET" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.TRACE_ID.getName() + "**：" + "4696.167.15928932046440001" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.REQUEST_URI.getName() + "**：" + "/api/health" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.REQUEST_PARAM.getName() + "**：" + "{a=a, b=b}" + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.EXCEPTION_MESSAGE.getName() + "**：" + exceptionMessage + System.getProperty("line.separator") +
                "**" + MDCConstantEnum.EXCEPTION_STACKTRACE.getName() + "**：" + System.getProperty("line.separator") +
                "`" + exceptionStackTrace + "`";
        WechatMarkDownMessage.Text markdown = new WechatMarkDownMessage.Text();
        markdown.setContent(content);
        message.setMarkdown(markdown);
        WeTalkUtils.sendMessage(message);
    }
}
